/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pt.utl.ist.isr.livetrack.server.impl;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import pt.utl.ist.isr.livetrack.server.interfaces.TimestampedFileCamera;
import pt.utl.ist.isr.livetrack.analysis.ImageUtils;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.TreeMap;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

/**
 *
 * @author David Miguel Antunes <davidmiguel [ at ] antunes.net>
 */
public class TimestampedFileCameraImpl extends DefaultCamera implements TimestampedFileCamera {

    private File dir;
    private long currentTime = 0;
    private TreeMap<Long, String> index = new TreeMap<Long, String>();
    private int framesPerSecond = 29;
    private BufferedImage bi;
    private boolean markTimestamp = false;

    public TimestampedFileCameraImpl() {
        super();
    }

    public TimestampedFileCameraImpl(String id, String dir) {
        super(id);
        setDir(dir);
    }

    @Override
    public synchronized String getDir() {
        return dir == null ? "" : dir.getAbsolutePath();
    }

    @Override
    public synchronized void setDir(String d) {
        dir = new File(d);
        File[] images = dir.listFiles();
        index.clear();
        for (File f : images) {
            if (f.isFile()) {
                String name = f.getName();
                if (name.matches(".*_.*_CAM.*\\..*(jpg|JPG|png|PNG|bmp|BMP)")) {
                    String[] tokens = name.split("_");
                    long timestamp = Long.parseLong(tokens[0]) * 1000 + Long.parseLong(tokens[1].substring(0, 3));
                    index.put(timestamp, name);
                } else if (name.matches("[0-9]*_CAM.*\\.(jpg|JPG|png|PNG|bmp|BMP)")) {
                    String[] tokens = name.split("_");
                    long timestamp = Long.parseLong(tokens[0]);
                    index.put(timestamp, name);
                }
            }
        }
        if (index.size() > 0) {
            currentTime = index.firstKey() - 1;
        }
    }

    @Override
    public synchronized int getFramesPerSecond() {
        return framesPerSecond;
    }

    @Override
    public synchronized void setFramesPerSecond(int framesPerSecond) {
        this.framesPerSecond = framesPerSecond;
    }

    @Override
    public synchronized boolean getMarkTimestamp() {
        return markTimestamp;
    }

    @Override
    public synchronized void setMarkTimestamp(boolean markTimestamp) {
        this.markTimestamp = markTimestamp;
        reprocessImage();
    }

    @Override
    public synchronized String getType() {
        return getClass().getSimpleName().replace("Impl", "");
    }

    @Override
    public synchronized void acquireImage() {
        if (index.lastKey() != null && currentTime < index.lastKey()) {
            long currentKey = index.higherKey(currentTime);
            long nextTime = currentTime + 1000 / framesPerSecond;
            long nextKey = index.higherKey(nextTime);

            if (currentKey != nextKey) {
                try {
                    File file = new File(dir.getAbsolutePath() + "/" + index.get(nextKey));
                    ImageInputStream iis = ImageIO.createImageInputStream(file);

                    String[] split = file.getName().split("\\.");
                    String extension = split[split.length - 1];

                    Iterator readers = ImageIO.getImageReadersByFormatName(extension);
                    ImageReader reader = (ImageReader) readers.next();

                    reader.setInput(iis, true);

                    ImageReadParam param = reader.getDefaultReadParam();

                    WIDTH = reader.getWidth(0);
                    HEIGHT = reader.getHeight(0);

                    if (bi == null || bi.getWidth() != WIDTH || bi.getHeight() != HEIGHT) {
                        WritableRaster wr = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, WIDTH, HEIGHT, 3, null);
                        bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
                        bi.setData(wr);
                    }

                    param.setDestination(bi);

                    bi = reader.read(0, param);

                    NCOMP = bi.getColorModel().getNumComponents();

                    if (iu == null || !iu.valid(WIDTH, HEIGHT, NCOMP)) {
                        iu = new ImageUtils(WIDTH, HEIGHT, NCOMP);
                    }
                    if (img == null || img.length != WIDTH * HEIGHT * NCOMP) {
                        img = iu.newImage();
                    }


                    iu.bufferedImageToArray(bi, img);

                } catch (IOException ex) {
                    logger.error(ex);
                }
                processNewImage();
            }

            currentTime = nextTime;
        }
    }

    @Override
    public synchronized void reset() {
        setDir(dir.toString());
    }

    @Override
    protected void postprocessImage(BufferedImage bi) {
        if (markTimestamp) {
            Graphics g = bi.getGraphics();

            g.setFont(g.getFont().deriveFont(Font.BOLD));
            g.setColor(Color.white);
            g.fillRect(10, 9, 85, 14);

            g.setColor(Color.black);
            g.drawString(
                    DateFormat.getTimeInstance(DateFormat.MEDIUM).format(new Date(currentTime)),
                    10,
                    20);
        }
    }
}
